package com.chuanyun.wechatcheckin.service;

import com.chuanyun.wechatcheckin.model.wechat.CheckinDataResponse;
import com.chuanyun.wechatcheckin.model.wechat.CheckinDayDataResponse;
import com.chuanyun.wechatcheckin.model.h3yun.H3yunResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.Instant;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 打卡数据同步服务
 * 整合企业微信打卡记录和日报数据，同步到氚云表中
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CheckinDataSyncService {

    private final WechatApiService wechatApiService;
    private final CheckinRecordService checkinRecordService;
    private final CheckinDayDataService checkinDayDataService;
    private final H3yunApiService h3yunApiService;
    private final ProjectLocationService projectLocationService;
    
    /**
     * 氚云打卡数据表的SchemaCode
     */
    private static final String CHECKIN_DATA_SCHEMA_CODE = "D290920af6e3dd1049244ce819748549a3a60a1";
    
    /**
     * 时间格式化器：年月日时分
     */
    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    
    /**
     * 同步指定日期范围的打卡数据到氚云
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 同步结果
     */
    public CheckinSyncResult syncCheckinDataByDateRange(LocalDate startDate, LocalDate endDate) {
        log.info("开始同步打卡数据到氚云，日期范围: {} 到 {}", startDate, endDate);
        
        CheckinSyncResult result = new CheckinSyncResult();
        result.setStartTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        result.setStartDate(startDate);
        result.setEndDate(endDate);
        
        try {
            // 1. 从氚云获取用户ID列表
            log.info("步骤1: 从氚云获取用户ID列表");
            List<String> userIds = getUserIdsFromH3yun();
            result.setTotalUserCount(userIds.size());
            log.info("从氚云获取到 {} 个用户ID", userIds.size());
            
            if (userIds.isEmpty()) {
                log.warn("氚云中没有用户数据，无法同步打卡数据");
                result.setSuccess(false);
                result.setErrorMessage("氚云中没有用户数据");
                return result;
            }
            
            // 2. 获取企业微信打卡记录数据
            log.info("步骤2: 获取企业微信打卡记录数据");
            Map<String, List<CheckinDataResponse.CheckinRecord>> checkinRecords = getCheckinRecords(userIds, startDate, endDate);
            result.setCheckinRecordCount(checkinRecords.values().stream().mapToInt(List::size).sum());
            log.info("获取到 {} 条打卡记录", result.getCheckinRecordCount());
            
            // 3. 获取企业微信打卡日报数据
            log.info("步骤3: 获取企业微信打卡日报数据");
            Map<String, List<CheckinDayDataResponse.DayData>> dayDataMap = getCheckinDayData(userIds, startDate, endDate);
            result.setDayDataCount(dayDataMap.values().stream().mapToInt(List::size).sum());
            log.info("获取到 {} 条日报数据", result.getDayDataCount());
            
            // 4. 整合数据并插入氚云
            log.info("步骤4: 整合数据并插入氚云");
            List<Map<String, Object>> integratedData = integrateCheckinData(checkinRecords, dayDataMap, startDate, endDate);
            result.setIntegratedDataCount(integratedData.size());
            log.info("整合后的数据条数: {}", integratedData.size());
            
            if (!integratedData.isEmpty()) {
                // 使用新增/更新逻辑替代批量插入
                int insertedCount = upsertCheckinData(integratedData, userIds, startDate, endDate);
                result.setInsertedCount(insertedCount);
                log.info("数据同步完成，新增/更新记录数: {}", insertedCount);
            } else {
                log.warn("没有需要同步的数据");
            }
            
            result.setSuccess(true);
            result.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            log.info("打卡数据同步完成");
            
        } catch (Exception e) {
            log.error("同步打卡数据失败", e);
            result.setSuccess(false);
            result.setErrorMessage(e.getMessage());
            result.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        
        return result;
    }
    
    /**
     * 同步昨天的打卡数据
     * @return 同步结果
     */
    public CheckinSyncResult syncYesterdayCheckinData() {
        LocalDate yesterday = LocalDate.now().minusDays(1);
        return syncCheckinDataByDateRange(yesterday, yesterday);
    }
    
    /**
     * 同步今天的打卡数据（使用当前时间作为结束时间）
     * @return 同步结果
     */
    public CheckinSyncResult syncTodayCheckinData() {
        CheckinSyncResult result = new CheckinSyncResult();
        LocalDate today = LocalDate.now();
        
        result.setStartDate(today);
        result.setEndDate(today);
        result.setStartTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        result.setSuccess(true);
        
        try {
            log.info("开始同步今天的打卡数据: {}", today);
            
            // 1. 获取用户ID列表
            List<String> userIds = getUserIdsFromH3yun();
            result.setTotalUserCount(userIds.size());
            log.info("获取到 {} 个用户", userIds.size());
            
            if (userIds.isEmpty()) {
                log.warn("未获取到任何用户，跳过同步");
                result.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                return result;
            }
            
            // 2. 获取今天的打卡记录（使用当前时间作为结束时间）
            Map<String, List<CheckinDataResponse.CheckinRecord>> checkinRecords = getTodayCheckinRecords(userIds);
            int checkinRecordCount = checkinRecords.values().stream().mapToInt(List::size).sum();
            result.setCheckinRecordCount(checkinRecordCount);
            log.info("获取到 {} 条打卡记录", checkinRecordCount);
            
            // 3. 获取今天的日报数据（使用当前时间作为结束时间）
            Map<String, List<CheckinDayDataResponse.DayData>> dayDataMap = getTodayCheckinDayData(userIds);
            int dayDataCount = dayDataMap.values().stream().mapToInt(List::size).sum();
            result.setDayDataCount(dayDataCount);
            log.info("获取到 {} 条日报数据", dayDataCount);
            
            // 4. 整合数据并同步到氚云
            List<Map<String, Object>> integratedData = integrateCheckinData(checkinRecords, dayDataMap, today, today);
            result.setIntegratedDataCount(integratedData.size());
            log.info("整合后数据条数: {}", integratedData.size());
            
            if (!integratedData.isEmpty()) {
                int insertedCount = upsertCheckinData(integratedData, userIds, today, today);
                result.setInsertedCount(insertedCount);
                log.info("成功同步 {} 条数据", insertedCount);
            }
            
            result.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            log.info("今天打卡数据同步完成");
            
        } catch (Exception e) {
            log.error("同步今天打卡数据失败", e);
            result.setSuccess(false);
            result.setErrorMessage(e.getMessage());
            result.setEndTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
        
        return result;
    }
    
    /**
     * 同步最近N天的打卡数据
     * @param days 天数
     * @return 同步结果
     */
    public CheckinSyncResult syncRecentCheckinData(int days) {
        LocalDate endDate = LocalDate.now().minusDays(1); // 昨天
        LocalDate startDate = endDate.minusDays(days - 1);
        return syncCheckinDataByDateRange(startDate, endDate);
    }
    
    /**
     * 从氚云获取用户ID列表
     */
    private List<String> getUserIdsFromH3yun() throws Exception {
        List<String> userIds = new ArrayList<>();
        int pageSize = 500;
        int currentPage = 1;
        boolean hasMoreData = true;
        
        while (hasMoreData) {
            log.debug("正在查询第 {} 页用户数据", currentPage);
            
            // 使用用户表的SchemaCode查询用户列表
            var response = h3yunApiService.queryBizDataByPage(
                "D29092097f0465225d541acabb2a9da271f5291", // 用户表SchemaCode
                pageSize,
                currentPage,
                List.of("UserId")
            );
            
            if (response.isSuccess() && response.getReturnData() != null) {
                List<Map<String, Object>> dataList = parseResponseData(response.getReturnData());
                
                if (dataList.isEmpty()) {
                    hasMoreData = false;
                } else {
                    for (Map<String, Object> data : dataList) {
                        Object userIdObj = data.get("UserId");
                        if (userIdObj != null) {
                            userIds.add(userIdObj.toString());
                        }
                    }
                    currentPage++;
                }
            } else {
                hasMoreData = false;
            }
        }
        
        log.info("从氚云获取到 {} 个用户ID", userIds.size());
        return userIds;
    }
    
    /**
     * 获取今天的打卡记录（使用当前时间作为结束时间）
     */
    private Map<String, List<CheckinDataResponse.CheckinRecord>> getTodayCheckinRecords(List<String> userIds) throws Exception {
        Map<String, List<CheckinDataResponse.CheckinRecord>> result = new HashMap<>();
        
        // 分批处理用户（每批最多100个）
        int batchSize = 100;
        for (int i = 0; i < userIds.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, userIds.size());
            List<String> batchUserIds = userIds.subList(i, endIndex);
            
            log.debug("获取第 {} 批用户的今天打卡记录，用户数: {}", (i / batchSize + 1), batchUserIds.size());
            
            // 使用专门的今天打卡记录方法（从今天0点到当前时间）
            List<CheckinDataResponse.CheckinRecord> records = checkinRecordService.getTodayCheckinRecords();
            
            // 过滤出当前批次的用户记录
            List<CheckinDataResponse.CheckinRecord> filteredRecords = records.stream()
                .filter(record -> batchUserIds.contains(record.getUserId()))
                .collect(Collectors.toList());
            
            // 按用户ID分组
            Map<String, List<CheckinDataResponse.CheckinRecord>> batchResult = filteredRecords.stream()
                .collect(Collectors.groupingBy(CheckinDataResponse.CheckinRecord::getUserId));
            
            result.putAll(batchResult);
        }
        
        return result;
    }
    
    /**
     * 获取今天的打卡日报数据（使用当前时间作为结束时间）
     */
    private Map<String, List<CheckinDayDataResponse.DayData>> getTodayCheckinDayData(List<String> userIds) throws Exception {
        Map<String, List<CheckinDayDataResponse.DayData>> result = new HashMap<>();
        
        // 分批处理用户（每批最多100个）
        int batchSize = 100;
        for (int i = 0; i < userIds.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, userIds.size());
            List<String> batchUserIds = userIds.subList(i, endIndex);
            
            log.debug("获取第 {} 批用户的今天日报数据，用户数: {}", (i / batchSize + 1), batchUserIds.size());
            
            // 使用专门的今天日报数据方法（从今天0点到当前时间）
            CheckinDayDataResponse response = checkinDayDataService.getTodayCheckinDayData(batchUserIds);
            
            if (response.getDatas() != null) {
                // 按用户ID分组
                Map<String, List<CheckinDayDataResponse.DayData>> batchResult = response.getDatas().stream()
                    .collect(Collectors.groupingBy(data -> data.getBaseInfo().getAcctId()));
                
                result.putAll(batchResult);
            }
        }
        
        return result;
    }
    
    /**
     * 获取打卡记录数据
     */
    private Map<String, List<CheckinDataResponse.CheckinRecord>> getCheckinRecords(
            List<String> userIds, LocalDate startDate, LocalDate endDate) throws Exception {
        
        Map<String, List<CheckinDataResponse.CheckinRecord>> result = new HashMap<>();
        
        // 分批处理用户（每批最多100个）
        int batchSize = 100;
        for (int i = 0; i < userIds.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, userIds.size());
            List<String> batchUserIds = userIds.subList(i, endIndex);
            
            log.debug("获取第 {} 批用户的打卡记录，用户数: {}", (i / batchSize + 1), batchUserIds.size());
            
            // 获取打卡记录（类型3表示全部打卡）
            LocalDateTime startDateTime = startDate.atStartOfDay();
            LocalDateTime endDateTime = endDate.atTime(23, 59, 59);
            
            List<CheckinDataResponse.CheckinRecord> records = checkinRecordService.getCheckinDataBatch(
                3, startDateTime, endDateTime, batchUserIds);
            
            // 按用户ID分组
            Map<String, List<CheckinDataResponse.CheckinRecord>> batchResult = records.stream()
                .collect(Collectors.groupingBy(CheckinDataResponse.CheckinRecord::getUserId));
            
            result.putAll(batchResult);
        }
        
        return result;
    }
    
    /**
     * 获取打卡日报数据
     */
    private Map<String, List<CheckinDayDataResponse.DayData>> getCheckinDayData(
            List<String> userIds, LocalDate startDate, LocalDate endDate) throws Exception {
        
        Map<String, List<CheckinDayDataResponse.DayData>> result = new HashMap<>();
        
        // 分批处理用户（每批最多100个）
        int batchSize = 100;
        for (int i = 0; i < userIds.size(); i += batchSize) {
            int endIndex = Math.min(i + batchSize, userIds.size());
            List<String> batchUserIds = userIds.subList(i, endIndex);
            
            log.debug("获取第 {} 批用户的日报数据，用户数: {}", (i / batchSize + 1), batchUserIds.size());
            
            CheckinDayDataResponse response = checkinDayDataService.getCheckinDayData(
                startDate, endDate, batchUserIds);
            
            if (response.getDatas() != null) {
                // 按用户ID分组
                Map<String, List<CheckinDayDataResponse.DayData>> batchResult = response.getDatas().stream()
                    .collect(Collectors.groupingBy(data -> data.getBaseInfo().getAcctId()));
                
                result.putAll(batchResult);
            }
        }
        
        return result;
    }
    
    /**
     * 新增或更新打卡数据到氚云
     * 每人每天首次记录新增，后续记录更新
     */
    private int upsertCheckinData(List<Map<String, Object>> integratedData, List<String> userIds, LocalDate startDate, LocalDate endDate) throws Exception {
        int processedCount = 0;
        Map<String, Map<String, Object>> userDateDataMap = new HashMap<>(); // 存储用户日期对应的数据，避免重复处理
        
        log.info("开始处理 {} 条打卡记录", integratedData.size());
        
        // 第一步：批量预查询氚云中已存在的记录
        Map<String, String> existingRecordsMap = batchQueryExistingRecords(userIds, startDate, endDate);
        log.info("预查询完成，找到 {} 条已存在的记录", existingRecordsMap.size());
        
        // 第二步：按用户日期分组，合并同一用户同一天的多条记录
        for (Map<String, Object> record : integratedData) {
            String userId = (String) record.get("acctid");
            String checkinDate = (String) record.get("CheckinDate");
            String userDateKey = userId + "_" + checkinDate;
            
            // 获取经纬度信息用于日志输出
            String latLngInfo = "";
            Object lat = record.get("lat");
            Object lng = record.get("lng");
            if (lat != null && lng != null) {
                // 转换为实际经纬度（企业微信返回的是实际值的1000000倍）
                double actualLat = ((Number) lat).longValue() / 1000000.0;
                double actualLng = ((Number) lng).longValue() / 1000000.0;
                latLngInfo = String.format(", 经纬度: %.6f,%.6f", actualLat, actualLng);
            }
            
            log.info("处理记录 - 用户ID: {}, 打卡日期: {}, 用户日期键: {}{}", userId, checkinDate, userDateKey, latLngInfo);
            
            if (!userDateDataMap.containsKey(userDateKey)) {
                // 首次遇到该用户该日期的记录，直接存储
                userDateDataMap.put(userDateKey, new HashMap<>(record));
                log.debug("首次记录用户 {} 日期 {} 的数据", userId, checkinDate);
            } else {
                // 已存在该用户该日期的记录，合并数据（这里可以根据业务需求决定如何合并）
                log.debug("用户 {} 日期 {} 已有记录，跳过重复数据", userId, checkinDate);
                // 注意：由于integrateCheckinData方法已经按用户日期整合了数据，
                // 理论上不应该出现重复的userDateKey，这里只是防御性编程
            }
        }
        
        // 第三步：基于预查询结果，对每个用户日期组合执行新增或更新操作
        for (Map.Entry<String, Map<String, Object>> entry : userDateDataMap.entrySet()) {
            String userDateKey = entry.getKey();
            Map<String, Object> record = entry.getValue();
            String userId = (String) record.get("acctid");
            String checkinDate = (String) record.get("CheckinDate");
            
            try {
                // 从预查询结果中检查是否已存在记录
                String existingRecordId = existingRecordsMap.get(userDateKey);
                
                if (existingRecordId != null) {
                    // 记录已存在，执行更新操作
                    log.info("准备更新记录 - 用户: {}, 日期: {}, 记录ID: {}, F0000014字段值: {}", 
                        userId, checkinDate, existingRecordId, record.get("F0000014"));
                    h3yunApiService.updateBizObject(CHECKIN_DATA_SCHEMA_CODE, existingRecordId, record, true);
                    log.info("更新用户 {} 日期 {} 的打卡记录，ID: {}", userId, checkinDate, existingRecordId);
                } else {
                    // 记录不存在，执行新增操作
                    log.info("准备新增记录 - 用户: {}, 日期: {}, F0000014字段值: {}", 
                        userId, checkinDate, record.get("F0000014"));
                    String newRecordId = h3yunApiService.createBizObject(CHECKIN_DATA_SCHEMA_CODE, record, true);
                    if (newRecordId != null) {
                        log.info("新增用户 {} 日期 {} 的打卡记录，ID: {}", userId, checkinDate, newRecordId);
                    } else {
                        log.warn("创建记录返回的ID为空，用户: {}, 日期: {}", userId, checkinDate);
                    }
                }
                processedCount++;
            } catch (Exception e) {
                log.error("处理用户 {} 日期 {} 的打卡记录时发生错误: {}", userId, checkinDate, e.getMessage(), e);
                // 继续处理其他记录，不中断整个流程
            }
        }
        
        log.info("打卡数据处理完成，成功处理 {} 条记录", processedCount);
        return processedCount;
    }
    
    /**
     * 批量预查询氚云中的打卡记录
     * @param userIds 用户ID列表
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 用户日期键到记录ID的映射
     */
    private Map<String, String> batchQueryExistingRecords(List<String> userIds, LocalDate startDate, LocalDate endDate) {
        Map<String, String> existingRecordsMap = new HashMap<>();
        
        try {
            // 构建查询条件：使用UserDateKey字段进行精确匹配
            List<String> userDateKeys = new ArrayList<>();
            for (String userId : userIds) {
                LocalDate currentDate = startDate;
                while (!currentDate.isAfter(endDate)) {
                    String userDateKey = userId + "_" + currentDate.toString();
                    userDateKeys.add(userDateKey);
                    currentDate = currentDate.plusDays(1);
                }
            }
            
            log.info("开始批量查询氚云记录，共 {} 个用户日期键", userDateKeys.size());
            
            // 获取氚云表单总记录数
            int totalRecords = getTotalRecordCount();
            log.info("氚云表单当前总记录数: {}", totalRecords);
            
            // 分批查询，避免查询条件过长，并支持自动分页
            int batchSize = 50; // 每批查询50个用户日期键
            int currentOffset = 0; // 当前查询偏移量
            int pageSize = 1000; // 每页查询记录数
            boolean hasMoreData = true; // 是否还有更多数据
            
            log.info("开始分页批量查询，每页 {} 条记录", pageSize);
            
            while (hasMoreData && currentOffset < totalRecords) {
                // 构建UserDateKey IN查询条件（如果有查询条件的话）
                List<Map<String, Object>> matchers = null;
                if (!userDateKeys.isEmpty()) {
                    // 分批处理用户日期键
                    int keyBatchStart = Math.min(currentOffset / pageSize * batchSize, userDateKeys.size());
                    int keyBatchEnd = Math.min(keyBatchStart + batchSize, userDateKeys.size());
                    
                    if (keyBatchStart < userDateKeys.size()) {
                        List<String> batchKeys = userDateKeys.subList(keyBatchStart, keyBatchEnd);
                        
                        matchers = new ArrayList<>();
                        Map<String, Object> userDateKeyMatcher = new HashMap<>();
                        userDateKeyMatcher.put("PropertyCode", "UserDateKey");
                        userDateKeyMatcher.put("PropertyType", 0); // 字符串类型
                        userDateKeyMatcher.put("MatchType", 8); // In操作符
                        userDateKeyMatcher.put("Value", batchKeys);
                        matchers.add(userDateKeyMatcher);
                        
                        log.debug("批量查询条件: UserDateKey IN {} (键范围: {}-{})", batchKeys, keyBatchStart, keyBatchEnd);
                    } else {
                        // 所有用户日期键都已处理完毕
                        log.info("所有用户日期键已处理完毕，结束查询");
                        break;
                    }
                }
                
                log.debug("查询条件详情: {}", matchers);
                
                // 执行分页查询
                H3yunResponse<Object> response = h3yunApiService.queryBizDataWithConditions(
                    CHECKIN_DATA_SCHEMA_CODE, currentOffset, pageSize, null, matchers);
                
                if (response != null && response.isSuccess()) {
                    List<Map<String, Object>> records = parseResponseData(response.getReturnData());
                    log.info("第 {} 页查询到 {} 条记录 (偏移量: {})", 
                            (currentOffset / pageSize) + 1, records.size(), currentOffset);
                    
                    // 调试：显示返回记录的UserDateKey
                    if (!records.isEmpty()) {
                        log.info("返回记录的UserDateKey示例: {}", 
                            records.stream().limit(3).map(r -> r.get("UserDateKey")).toArray());
                        
                        // 如果有查询条件，统计实际匹配的记录数
                        if (matchers != null && !matchers.isEmpty()) {
                            List<String> currentBatchKeys = (List<String>) matchers.get(0).get("Value");
                            long matchedCount = records.stream()
                                .map(r -> r.get("UserDateKey"))
                                .filter(currentBatchKeys::contains)
                                .count();
                            log.info("返回记录总数: {}, 实际匹配的UserDateKey数量: {}", 
                                records.size(), matchedCount);
                        }
                    }
                    
                    // 处理查询结果
                    for (Map<String, Object> record : records) {
                        String recordId = (String) record.get("ObjectId");
                        String userDateKey = (String) record.get("UserDateKey");
                        
                        if (recordId != null && userDateKey != null) {
                            existingRecordsMap.put(userDateKey, recordId);
                            log.debug("找到已存在记录: UserDateKey={}, ObjectId={}", userDateKey, recordId);
                        }
                    }
                    
                    // 判断是否还有更多数据
                    if (records.size() < pageSize) {
                        // 返回的记录数少于页面大小，说明已经是最后一页
                        hasMoreData = false;
                        log.info("已到达最后一页，查询结束");
                    } else {
                        // 更新偏移量，准备查询下一页
                        currentOffset += pageSize;
                        log.debug("准备查询下一页，新偏移量: {}", currentOffset);
                    }
                } else {
                    log.warn("第 {} 页查询失败: {}", (currentOffset / pageSize) + 1, 
                            response != null ? response.getErrorMessage() : "响应为空");
                    // 查询失败时也要停止循环，避免无限重试
                    hasMoreData = false;
                }
            }
            
        } catch (Exception e) {
            log.error("批量查询氚云记录时发生错误", e);
        }
        
        log.info("批量查询完成，找到 {} 条已存在的记录", existingRecordsMap.size());
        return existingRecordsMap;
    }
    
    /**
     * 检查日期是否在指定范围内
     */
    private boolean isDateInRange(String dateStr, LocalDate startDate, LocalDate endDate) {
        try {
            LocalDate date = LocalDate.parse(dateStr);
            return !date.isBefore(startDate) && !date.isAfter(endDate);
        } catch (Exception e) {
            log.warn("解析日期字符串失败: {}", dateStr);
            return false;
        }
    }
    private String findExistingRecord(String userId, String checkinDate) {
        try {
            // 使用现有的queryBizData方法查询前10条记录
            List<String> returnItems = List.of("ObjectId", "F0000001", "F0000003"); // 只返回必要字段
            H3yunResponse<Object> response = h3yunApiService.queryBizData(CHECKIN_DATA_SCHEMA_CODE, 1, 10, returnItems);
            
            if (response.isSuccess()) {
                List<Map<String, Object>> records = parseResponseData(response.getReturnData());
                
                if (records != null && !records.isEmpty()) {
                    // 在返回的记录中查找匹配的用户ID和日期
                    for (Map<String, Object> record : records) {
                        String recordUserId = (String) record.get("F0000001");
                        String recordDate = (String) record.get("F0000003");
                        
                        if (userId.equals(recordUserId) && checkinDate.equals(recordDate)) {
                            return (String) record.get("ObjectId");
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("查询用户 {} 日期 {} 的现有记录时发生错误: {}", userId, checkinDate, e.getMessage());
        }
        return null;
    }

    /**
     * 获取氚云表单的总记录数
     */
    private int getTotalRecordCount() {
        try {
            // 查询第一页数据，获取总记录数信息
            List<String> returnItems = List.of("ObjectId"); // 只返回ObjectId字段
            H3yunResponse<Object> response = h3yunApiService.queryBizData(CHECKIN_DATA_SCHEMA_CODE, 1, 1, returnItems);
            
            if (response.isSuccess()) {
                // 从响应中解析总记录数（如果API返回了这个信息）
                // 注意：这里需要根据实际的API响应结构来获取总记录数
                // 如果API不直接返回总记录数，可能需要通过其他方式获取
                log.debug("查询总记录数响应: {}", response);
                
                // 临时方案：返回一个较大的数值，确保分页查询能正常进行
                // 实际使用时应该根据API文档或响应结构来获取真实的总记录数
                return Integer.MAX_VALUE;
            } else {
                log.warn("查询氚云表单总记录数失败: {}", response.getErrorMessage());
                return 0;
            }
        } catch (Exception e) {
            log.error("获取氚云表单总记录数时发生错误", e);
            return 0;
        }
    }
    
    /**
     * 整合打卡数据和日报数据
     */
    private List<Map<String, Object>> integrateCheckinData(
            Map<String, List<CheckinDataResponse.CheckinRecord>> checkinRecords,
            Map<String, List<CheckinDayDataResponse.DayData>> dayDataMap,
            LocalDate startDate, LocalDate endDate) {
        
        List<Map<String, Object>> integratedData = new ArrayList<>();
        
        // 获取所有用户ID
        Set<String> allUserIds = new HashSet<>();
        allUserIds.addAll(checkinRecords.keySet());
        allUserIds.addAll(dayDataMap.keySet());
        
        log.info("开始整合数据，用户数量: {}", allUserIds.size());
        
        // 遍历每个用户
        for (String userId : allUserIds) {
            List<CheckinDataResponse.CheckinRecord> userCheckinRecords = 
                checkinRecords.getOrDefault(userId, new ArrayList<>());
            List<CheckinDayDataResponse.DayData> userDayData = 
                dayDataMap.getOrDefault(userId, new ArrayList<>());
            
            // 遍历日期范围
            LocalDate currentDate = startDate;
            while (!currentDate.isAfter(endDate)) {
                Map<String, Object> record = createIntegratedRecord(userId, currentDate, 
                    userCheckinRecords, userDayData);
                if (record != null) {
                    integratedData.add(record);
                }
                currentDate = currentDate.plusDays(1);
            }
        }
        
        return integratedData;
    }
    
    /**
     * 创建整合后的记录
     */
    private Map<String, Object> createIntegratedRecord(
            String userId, LocalDate date,
            List<CheckinDataResponse.CheckinRecord> checkinRecords,
            List<CheckinDayDataResponse.DayData> dayDataList) {
        
        Map<String, Object> record = new HashMap<>();
        
        // 查找当天的日报数据
        CheckinDayDataResponse.DayData dayData = dayDataList.stream()
            .filter(data -> {
                if (data.getBaseInfo() != null && data.getBaseInfo().getDate() != null) {
                    // 假设date字段是时间戳格式，需要转换为日期进行比较
                    LocalDate dataDate = LocalDate.ofEpochDay(data.getBaseInfo().getDate() / (24 * 60 * 60));
                    return dataDate.equals(date);
                }
                return false;
            })
            .findFirst()
            .orElse(null);
        
        // 查找当天的打卡记录
        List<CheckinDataResponse.CheckinRecord> dayCheckinRecords = checkinRecords.stream()
            .filter(record1 -> {
                if (record1.getCheckinTime() != null) {
                    LocalDate recordDate = LocalDate.ofEpochDay(record1.getCheckinTime() / (24 * 60 * 60));
                    return recordDate.equals(date);
                }
                return false;
            })
            .collect(Collectors.toList());
        
        // 如果既没有日报数据也没有打卡记录，则不创建记录
        if (dayData == null && dayCheckinRecords.isEmpty()) {
            return null;
        }
        
        // 填充用户需要的字段
        fillRequiredFields(record, userId, date, dayData, dayCheckinRecords);
        
        return record;
    }
    
    /**
     * 填充用户需要的字段
     * 字段包括：员工姓名，打卡人员账号，记录类型，打卡规则名称，规则id，上班时间，下班时间，
     * 当日最早打卡时间，当日最晚打卡时间，假期类型
     */
    private void fillRequiredFields(Map<String, Object> record, String userId, LocalDate date,
                                   CheckinDayDataResponse.DayData dayData, 
                                   List<CheckinDataResponse.CheckinRecord> dayCheckinRecords) {
        
        // 基础信息
        record.put("acctid", userId); // 打卡人员账号
        record.put("CheckinDate", date.toString());
        
        // 添加用户日期键，用于快速匹配和更新检查
        String userDateKey = userId + "_" + date.toString();
        record.put("UserDateKey", userDateKey);
        
        // 从日报数据获取字段
        if (dayData != null && dayData.getBaseInfo() != null) {
            var baseInfo = dayData.getBaseInfo();
            record.put("userName", baseInfo.getName()); // 打卡人员姓名
            record.put("F0000002", baseInfo.getName()); // F0000002字段，用打卡人员姓名填充
            record.put("recordType", baseInfo.getRecordType()); // 记录类型
            record.put("groupname", baseInfo.getRuleInfo() != null ? baseInfo.getRuleInfo().getGroupName() : null); // 打卡规则名称
            
            // 从规则信息中获取上班时间和下班时间
            if (baseInfo.getRuleInfo() != null && baseInfo.getRuleInfo().getCheckinTime() != null && 
                !baseInfo.getRuleInfo().getCheckinTime().isEmpty()) {
                var checkinTime = baseInfo.getRuleInfo().getCheckinTime().get(0);
                record.put("workSec", formatSecondsFromMidnight(checkinTime.getWorkSec())); // 上班时间
                record.put("offWorkSec", formatSecondsFromMidnight(checkinTime.getOffWorkSec())); // 下班时间
            }
        }
        
        // 从日报数据获取最早最晚打卡时间
        if (dayData != null && dayData.getSummaryInfo() != null) {
            var summary = dayData.getSummaryInfo();
            // 获取日期的Unix时间戳
            Long dateTimestamp = dayData.getBaseInfo() != null ? dayData.getBaseInfo().getDate() : null;
            
            // 检查最早打卡时间是否早于8点
            boolean isEarlyCheckin = isEarlierThan8AM(summary.getEarliestTime());
            
            if (isEarlyCheckin) {
                // 如果最早打卡时间早于8点，将最早和最晚打卡时间设置为空
                log.info("用户 {} 在 {} 的最早打卡时间早于8点，将最早和最晚打卡时间设置为空", userId, date);
                record.put("earliestTime", null); // 当日最早打卡时间设为空
                record.put("lastestTime", null); // 当日最晚打卡时间设为空
            } else {
                // 正常情况下设置最早和最晚打卡时间
                record.put("earliestTime", formatTimeWithDate(dateTimestamp, summary.getEarliestTime())); // 当日最早打卡时间
                record.put("lastestTime", formatTimeWithDate(dateTimestamp, summary.getLastestTime())); // 当日最晚打卡时间
            }
        }
        
        // 从日报数据获取假期类型
        if (dayData != null && dayData.getHolidayInfos() != null && !dayData.getHolidayInfos().isEmpty()) {
            // 假勤类型信息 - 从sp_title获取标题文本
            var holidayInfo = dayData.getHolidayInfos().get(0);
            if (holidayInfo.getSpTitle() != null && holidayInfo.getSpTitle().getData() != null && 
                !holidayInfo.getSpTitle().getData().isEmpty()) {
                record.put("spItemsType", holidayInfo.getSpTitle().getData().get(0).getText());
            }
        }
        
        // 从打卡记录获取字段
        if (!dayCheckinRecords.isEmpty()) {
            // 按时间排序
            dayCheckinRecords.sort(Comparator.comparing(CheckinDataResponse.CheckinRecord::getCheckinTime));
            
            CheckinDataResponse.CheckinRecord firstRecord = dayCheckinRecords.get(0);
            
            // 规则ID（从第一条记录获取）
            record.put("groupid", firstRecord.getGroupId()); // 规则id
            
            // 保存经纬度信息到record中
            record.put("lat", firstRecord.getLat());
            record.put("lng", firstRecord.getLng());
            
            // 地理位置匹配项目名称
            try {
                // 转换为实际经纬度（企业微信返回的是实际值的1000000倍）
                double actualLat = firstRecord.getLat() / 1000000.0;
                double actualLng = firstRecord.getLng() / 1000000.0;
                
                log.info("开始进行地理位置匹配 - 用户: {}, 日期: {}, 经纬度: {},{} (原始值: {},{})", 
                    userId, date, actualLat, actualLng, firstRecord.getLat(), firstRecord.getLng());
                
                String matchedProject = projectLocationService.matchNearestProject(
                    firstRecord.getLat(), firstRecord.getLng());
                    
                if (matchedProject != null) {
                    record.put("F0000014", matchedProject); // 将匹配的项目名称填入F0000014字段
                    log.info("地理位置匹配成功 - 用户: {}, 日期: {}, 经纬度: {},{}, 匹配项目: {}, F0000014字段已设置: {}", 
                        userId, date, actualLat, actualLng, matchedProject, record.get("F0000014"));
                } else {
                    log.warn("地理位置匹配失败 - 用户: {}, 日期: {}, 经纬度: {},{}, 未找到匹配的项目", 
                        userId, date, actualLat, actualLng);
                }
            } catch (Exception e) {
                double actualLat = firstRecord.getLat() / 1000000.0;
                double actualLng = firstRecord.getLng() / 1000000.0;
                log.error("地理位置匹配异常 - 用户: {}, 日期: {}, 经纬度: {},{}, 异常信息: {}", 
                    userId, date, actualLat, actualLng, e.getMessage(), e);
            }
        }
    }
    
    /**
     * 解析氚云API返回的数据
     */
    @SuppressWarnings("unchecked")
    private List<Map<String, Object>> parseResponseData(Object returnData) {
        if (returnData == null) {
            return new ArrayList<>();
        }
        
        log.debug("氚云返回数据类型: {}", returnData.getClass().getSimpleName());
        
        if (returnData instanceof List) {
            // 如果返回的是List，直接转换
            List<Map<String, Object>> dataList = (List<Map<String, Object>>) returnData;
            log.debug("直接解析List，数据条数: {}", dataList.size());
            return dataList;
        } else if (returnData instanceof Map) {
            // 如果返回的是Map，可能包含BizObject字段（单个对象）或BizObjectArray字段（多个对象）
            Map<String, Object> dataMap = (Map<String, Object>) returnData;
            log.debug("返回Map结构，包含字段: {}", dataMap.keySet());
            
            // 首先检查是否是单个BizObject（根据新的返回格式）
            Object bizObject = dataMap.get("BizObject");
            if (bizObject instanceof Map) {
                // 单个业务对象，包装成List返回
                List<Map<String, Object>> dataList = new ArrayList<>();
                dataList.add((Map<String, Object>) bizObject);
                log.debug("解析单个BizObject，数据条数: 1");
                return dataList;
            }
            
            // 尝试多种可能的数组字段名
            Object bizObjectArray = dataMap.get("BizObjectArray");
            if (bizObjectArray == null) {
                bizObjectArray = dataMap.get("Data");
            }
            if (bizObjectArray == null) {
                bizObjectArray = dataMap.get("Items");
            }
            if (bizObjectArray == null) {
                bizObjectArray = dataMap.get("List");
            }
            if (bizObjectArray == null) {
                // 如果没有找到预期的字段，尝试找到第一个List类型的值
                for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                    if (entry.getValue() instanceof List) {
                        bizObjectArray = entry.getValue();
                        log.debug("找到List类型字段: {}", entry.getKey());
                        break;
                    }
                }
            }
            
            if (bizObjectArray instanceof List) {
                List<Map<String, Object>> dataList = (List<Map<String, Object>>) bizObjectArray;
                log.debug("从Map中解析List，数据条数: {}", dataList.size());
                return dataList;
            } else if (bizObjectArray != null) {
                log.warn("氚云返回数据格式异常，BizObjectArray不是List类型: {}, 类型: {}", 
                        bizObjectArray, bizObjectArray.getClass().getSimpleName());
            } else {
                log.warn("氚云返回Map中未找到数据数组字段，Map内容: {}", dataMap);
            }
        } else {
            log.warn("氚云返回数据格式异常，不是List或Map类型: {}", returnData.getClass());
        }
        
        return new ArrayList<>();
    }
    
    /**
     * 将Unix时间戳转换为年月日时分格式
     * @param timestamp Unix时间戳（秒）
     * @return 格式化后的时间字符串，格式为 yyyy-MM-dd HH:mm
     */
    private String formatTimestamp(Long timestamp) {
        if (timestamp == null || timestamp <= 0) {
            return null;
        }
        
        try {
            Instant instant = Instant.ofEpochSecond(timestamp);
            LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.of("Asia/Shanghai"));
            return dateTime.format(TIME_FORMATTER);
        } catch (Exception e) {
            log.warn("时间戳转换失败: {}", timestamp, e);
            return null;
        }
    }
    
    /**
     * 将距离0点的时间差（秒）转换为时分格式
     * @param secondsFromMidnight 距离0点的时间差（秒）
     * @return 格式化后的时间字符串，格式为 HH:mm
     */
    private String formatSecondsFromMidnight(Long secondsFromMidnight) {
        if (secondsFromMidnight == null || secondsFromMidnight < 0) {
            return null;
        }
        
        try {
            int hours = (int) (secondsFromMidnight / 3600);
            int minutes = (int) ((secondsFromMidnight % 3600) / 60);
            return String.format("%02d:%02d", hours, minutes);
        } catch (Exception e) {
            log.warn("时间差转换失败: {}", secondsFromMidnight, e);
            return null;
        }
    }
    
    /**
     * 将Unix时间戳日期和距离0点的秒数组合成完整的时间格式
     * @param dateTimestamp 日期的Unix时间戳
     * @param secondsFromMidnight 距离0点的时间差（秒）
     * @return 格式化后的时间字符串，格式为 yyyy-MM-dd HH:mm
     */
    private String formatTimeWithDate(Long dateTimestamp, Long secondsFromMidnight) {
        if (dateTimestamp == null || dateTimestamp <= 0 || 
            secondsFromMidnight == null || secondsFromMidnight < 0) {
            return null;
        }
        
        try {
            // 将Unix时间戳转换为LocalDate
            Instant dateInstant = Instant.ofEpochSecond(dateTimestamp);
            LocalDate date = LocalDate.ofInstant(dateInstant, ZoneId.of("Asia/Shanghai"));
            
            // 计算时分
            int hours = (int) (secondsFromMidnight / 3600);
            int minutes = (int) ((secondsFromMidnight % 3600) / 60);
            
            // 组合成完整的日期时间
            LocalDateTime dateTime = date.atTime(hours, minutes);
            return dateTime.format(TIME_FORMATTER);
        } catch (Exception e) {
            log.warn("时间组合转换失败: dateTimestamp={}, secondsFromMidnight={}", 
                    dateTimestamp, secondsFromMidnight, e);
            return null;
        }
    }
    
    /**
     * 判断给定的时间（距离0点的秒数）是否早于8点
     * @param secondsFromMidnight 距离0点的秒数
     * @return 如果早于8点返回true，否则返回false
     */
    private boolean isEarlierThan8AM(Long secondsFromMidnight) {
        if (secondsFromMidnight == null || secondsFromMidnight < 0) {
            return false;
        }
        
        // 8点 = 8 * 3600 = 28800秒
        long eightAMSeconds = 8 * 3600;
        return secondsFromMidnight < eightAMSeconds;
    }
    
    /**
     * 同步结果类
     */
    public static class CheckinSyncResult {
        private String startTime;
        private String endTime;
        private LocalDate startDate;
        private LocalDate endDate;
        private boolean success;
        private String errorMessage;
        private int totalUserCount;
        private int checkinRecordCount;
        private int dayDataCount;
        private int integratedDataCount;
        private int insertedCount;
        
        // Getters and Setters
        public String getStartTime() { return startTime; }
        public void setStartTime(String startTime) { this.startTime = startTime; }
        
        public String getEndTime() { return endTime; }
        public void setEndTime(String endTime) { this.endTime = endTime; }
        
        public LocalDate getStartDate() { return startDate; }
        public void setStartDate(LocalDate startDate) { this.startDate = startDate; }
        
        public LocalDate getEndDate() { return endDate; }
        public void setEndDate(LocalDate endDate) { this.endDate = endDate; }
        
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        
        public String getErrorMessage() { return errorMessage; }
        public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
        
        public int getTotalUserCount() { return totalUserCount; }
        public void setTotalUserCount(int totalUserCount) { this.totalUserCount = totalUserCount; }
        
        public int getCheckinRecordCount() { return checkinRecordCount; }
        public void setCheckinRecordCount(int checkinRecordCount) { this.checkinRecordCount = checkinRecordCount; }
        
        public int getDayDataCount() { return dayDataCount; }
        public void setDayDataCount(int dayDataCount) { this.dayDataCount = dayDataCount; }
        
        public int getIntegratedDataCount() { return integratedDataCount; }
        public void setIntegratedDataCount(int integratedDataCount) { this.integratedDataCount = integratedDataCount; }
        
        public int getInsertedCount() { return insertedCount; }
        public void setInsertedCount(int insertedCount) { this.insertedCount = insertedCount; }
        
        @Override
        public String toString() {
            return String.format(
                "CheckinSyncResult{startTime='%s', endTime='%s', startDate=%s, endDate=%s, " +
                "success=%s, errorMessage='%s', totalUserCount=%d, checkinRecordCount=%d, " +
                "dayDataCount=%d, integratedDataCount=%d, insertedCount=%d}",
                startTime, endTime, startDate, endDate, success, errorMessage,
                totalUserCount, checkinRecordCount, dayDataCount, integratedDataCount, insertedCount
            );
        }
    }
}